﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FantastPlatform.Framework.IService;
using FantastPlatform.Framework.IModel;
using FantastPlatform.Framework.Model;
using NHibernate;
using NHibernate.Criterion;
using System.Security.Cryptography;
using FantastPlatform.Framework.Common;
using System.Data.SqlClient;
using System.Data;
using NHibernate.SqlCommand;
using FantastPlatform.Framework.Exception;
using FantastPlatform.Framework.Core;

namespace FantastPlatform.Framework.Service
{
    public class UserService : DataService<IUser, User>, IUserService
    {
        private void CheckUser(IUser user)
        {
            Check.Require<ArgumentNullException>(user != null, "用户不能为null！");
           // Check.Require<ArgumentNullException>(!string.IsNullOrEmpty(user.Email), "用户的邮箱地址不能为空！");
            //CheckParameter.ObjectNotExisted(!IsEmailExisted(user.Email), string.Format("邮箱为：{0}的用户已经存在！", user.Email));
            //Check.Require<InvalidEmailException>(user.Email, "用户的邮箱地址", Check.Email);
           // Check.Require<InvalidLengthException>(user.Email.Length, "用户的邮箱地址", new BetweenStrategy<int>(1, 50));
            Check.Require<ArgumentNullException>(!string.IsNullOrEmpty(user.Name), "用户名称不能为空！");
            Check.Require<InvalidLengthException>(user.Name.Length, "用户名称", new BetweenStrategy<int>(1, 50));
            //Check.Require<InvalidCodeException>(!Tools.IsChinese(user.Code), "用户编号不能为中文！");
            Check.Require<ArgumentNullException>(!string.IsNullOrEmpty(user.Password), "用户密码不能为空！");
            Check.Require<InvalidLengthException>(user.Password.Length, "用户密码", new BetweenStrategy<int>(1, 50));

        }
        public override object Create(IUser entity)
        {
            CheckUser(entity);
            Check.Require<ObjectExistedException>(!IsNameExisted(entity.Name), string.Format("用户名为：{0}的用户已经存在！", entity.Name));

            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            string password = string.Empty;
            password = BitConverter.ToString(md5.ComputeHash(UTF8Encoding.Default.GetBytes(entity.Password)));
            entity.Password = password.Replace("-", "");
            return base.Create(entity);
        }

        private bool IsNameExisted(string p)
        {
            IList<User> list = Session.CreateCriteria(typeof(User)).Add(Expression.Eq("Name", p)).List<User>();
            return !CollectionHelper.IsNullOrEmpty<User>(list);
        }

        public override void Update(IUser entity)
        {
            CheckUser(entity);
            IUser oldUser = Load(entity.Id);
            if (entity.Name != oldUser.Name)
            {
                Check.Require<ObjectExistedException>(!IsNameExisted(entity.Name), string.Format("用户名：{0}已经存在，您不能使用此用户名", entity.Name));
            }
            if (!entity.Password.Equals(oldUser.Password))
            {
                MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
                string password = string.Empty;
                password = BitConverter.ToString(md5.ComputeHash(UTF8Encoding.Default.GetBytes(entity.Password)));
                oldUser.Password = password.Replace("-", "");
            }
            oldUser.Name = entity.Name;
            oldUser.Code = entity.Code;
            oldUser.Description = entity.Description;

            base.Update(oldUser);
        }

        #region IUserService 成员


        public IList<IResource> GetResource(int userId)
        {
            ICriteria criteria = Session.CreateCriteria(typeof(Permission)).CreateCriteria("Roles").CreateAlias("Users", "u")
                .Add(Expression.Eq("u.Id", userId)).Add(Expression.Eq("Enable",true));
            return criteria.List<IPermission>().Select(c => c.Resource).ToList<IResource>();
        }

        public IList<IOperation> GetOperations(IUser user, IResource resource)
        {
            var permissions = Session.CreateQuery(@"from Permission p left join fetch p.Roles r
                                                left join fetch r.Users u
                                                left join fetch p.Resource s
                                                where u.Id=:userId and s.Id=:resourceId")
                     .SetInt32("userId", user.Id).SetInt32("resourceId", resource.Id).List<IPermission>();

            return permissions.Select(c => c.Operation).ToList();
        }

        public IList<IRole> GetRoles(string keywords,IList<Sort> sorts, int userId, int page, int pageSize, out int totoalCount)
        {
            ICriteria criteria = Session.CreateCriteria(typeof(Role)).CreateAlias("Users", "u")
                .Add(Expression.Eq("u.Id", userId)).Add(Expression.Eq("Enable", true));
            criteria=AddOrderBySorts(criteria, sorts);
            if (string.IsNullOrEmpty(keywords))
                criteria.Add(Expression.Like("Name", keywords, MatchMode.Anywhere));
            ICriteria clone = criteria.Clone() as ICriteria;
            totoalCount = int.Parse(clone.SetProjection(Projections.RowCount()).UniqueResult().ToString());
            return criteria.SetFirstResult((page - 1) * pageSize).SetMaxResults(pageSize).List<IRole>();
        }

        #endregion

        #region IUserService 成员


        public IUser Login(string name, string password)
        {
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            string md5Password = BitConverter.ToString(md5.ComputeHash(UTF8Encoding.Default.GetBytes(password)));
            md5Password = md5Password.Replace("-", "");
            ICriteria criteria = Session.CreateCriteria(typeof(User))
                .Add(Expression.Eq("Name", name)).Add(Expression.Eq("Password", md5Password)).Add(Expression.Eq("Enable", true));
            IUser user = criteria.UniqueResult<IUser>();
            Check.Require <FrameworkException>(user != null, "用户名或者密码错误！");
            return user; 
        }
          
        public IList<IUser> LoadNotUsedUsers(string keywords,IList<Sort> sorts, int page, int pageSize, out int totoalCount)
        {
            ICriteria criteria = Session.CreateCriteria(typeof(User)).CreateAlias("Employees", "e", JoinType.LeftOuterJoin)
                .Add(Expression.Eq("Enable",true)).Add(Expression.IsNull("e.Id"));
            criteria = AddOrderBySorts(criteria, sorts);
            if (!string.IsNullOrEmpty(keywords))
                criteria.Add(Expression.Like("Name", keywords, MatchMode.Anywhere));
            ICriteria clone = criteria.Clone() as ICriteria;
            totoalCount = int.Parse(clone.SetProjection(Projections.RowCount()).UniqueResult().ToString());
            return criteria.SetFirstResult((page - 1) * pageSize).SetMaxResults(pageSize).List<IUser>();
        }

        public void AddRoles(int userId, IList<int> roleIds)
        {
            ITransaction tan = null;
            TransactionDelegate t = (ITransaction transaction) =>
                {
                    IUser user = Get(userId);
                    Check.Require<ObjectNotExistedException>(user != null, "当前用户不存在！");
                    IDbCommand command = Session.Connection.CreateCommand();
                    transaction.Enlist(command);
                    DataTable dataTable = new DataTable();
                    dataTable.Columns.Add("UserId");
                    dataTable.Columns.Add("RoleId");
                    foreach (int i in roleIds)
                    {
                        if (!user.Roles.Select(c => c.Id).Contains<int>(i))
                        {
                            Check.Require<ObjectNotExistedException>(Session.Get<Role>(i) != null, string.Format("Id为{0}的角色不存在！", i));
                            DataRow dataRow = dataTable.NewRow();
                            dataRow["UserId"] = userId;
                            dataRow["RoleId"] = i;
                            dataTable.Rows.Add(dataRow);
                        }
                    }
                    command.CommandText = "insert into User_UserRole(UserId,RoleId) values(@UserId,@RoleId)";
                    SqlParameter roleId = new SqlParameter();
                    roleId.ParameterName = "@RoleId";
                    roleId.SqlDbType = SqlDbType.Int;
                    roleId.SourceColumn = "RoleId";
                    SqlParameter userIdp = new SqlParameter();
                    userIdp.ParameterName = "@UserId";
                    userIdp.SqlDbType = SqlDbType.Int;
                    userIdp.SourceColumn = "UserId";
                    command.Parameters.Add(roleId);
                    command.Parameters.Add(userIdp);
                    SqlDataAdapter sqlDataAdapter = new SqlDataAdapter();
                    sqlDataAdapter.InsertCommand = command as SqlCommand;
                    sqlDataAdapter.Update(dataTable);
                };
            ExecuteTransaction(t, tan);
        }

        public void RemoveRoles(int userId, IList<int> roleIds)
        {
            ITransaction tan = null;
            TransactionDelegate t = (ITransaction transaction) =>
                {
                    IUser user = Get(userId);
                    Check.Require<ObjectNotExistedException>(user != null, "当前用户不存在！");
                    foreach (int i in roleIds)
                    {
                        Check.Require<ObjectNotExistedException>(Session.Get<Role>(i) != null, string.Format("Id为{0}的角色不存在！", i));
                        Session.CreateSQLQuery(string.Format("delete from User_UserRole where UserId={0} and RoleId={1}", userId, i)).ExecuteUpdate();
                    }
                };
            ExecuteTransaction(t, tan);
        }
         
        public IList<IUser> LoadUsersNotExsit(string keywords,IList<Sort> sorts, int roleId, int page, int pageSize, out int totoalCount)
        {
            ICriteria criteria = Session.CreateCriteria(typeof(User)).Add(Expression.Eq("Enable",true))
                .Add(Expression.Sql(string.Format("not exists(select * from User_UserRole where UserId=this_.Id and RoleId={0})", roleId)));
           criteria=AddOrderBySorts(criteria, sorts);
            if (!string.IsNullOrEmpty(keywords))
                criteria.Add(Expression.Like("Name", keywords, MatchMode.Anywhere));
            ICriteria clone = criteria.Clone() as ICriteria;
            totoalCount = int.Parse(clone.SetProjection(Projections.RowCount()).UniqueResult().ToString());
            return criteria.SetFirstResult((page - 1) * pageSize).SetMaxResults(pageSize).List<IUser>();
        }

        public override void DeleteReally(List<int> ids)
        {
            List<string> tables = new List<string>();
            tables.Add("User_UserRole");
            tables.Add("Org_EmployeeUser");
            base.DeleteReallyAndRelations(ids, tables);
        }
        #endregion
    }
}
